using UnityEngine;
using System.Collections.Generic;

/// <summary>
/// GC监控工具 - 帮助检测GC分配问题
/// </summary>
public class GCMonitor : MonoBehaviour
{
    private static GCMonitor m_Instance;
    public static GCMonitor Instance
    {
        get
        {
            if (m_Instance == null)
            {
                m_Instance = FindObjectOfType<GCMonitor>();
                if (m_Instance == null)
                {
                    GameObject go = new GameObject("GCMonitor");
                    m_Instance = go.AddComponent<GCMonitor>();
                }
            }
            return m_Instance;
        }
    }
    
    [Header("GC监控设置")]
    public bool EnableMonitoring = true;
    public float UpdateInterval = 1.0f;
    public int GCWarningThreshold = 100; // GC分配警告阈值
    
    private float m_LastUpdateTime;
    private long m_LastGCCollectionCount;
    private int m_CurrentFrameGCAllocations;
    private int m_MaxFrameGCAllocations;
    
    private Dictionary<string, int> m_GCAllocationSources = new Dictionary<string, int>();
    
    private void Awake()
    {
        if (m_Instance == null)
        {
            m_Instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else if (m_Instance != this)
        {
            Destroy(gameObject);
        }
    }
    
    private void Update()
    {
        if (!EnableMonitoring) return;
        
        // 监控GC分配
        MonitorGCAllocations();
        
        // 定期更新统计信息
        if (Time.time - m_LastUpdateTime >= UpdateInterval)
        {
            UpdateGCStatistics();
            m_LastUpdateTime = Time.time;
        }
    }
    
    /// <summary>
    /// 监控GC分配
    /// </summary>
    private void MonitorGCAllocations()
    {
        long currentGCCollectionCount = System.GC.CollectionCount(0);
        
        if (currentGCCollectionCount > m_LastGCCollectionCount)
        {
            m_CurrentFrameGCAllocations++;
            m_MaxFrameGCAllocations = Mathf.Max(m_MaxFrameGCAllocations, m_CurrentFrameGCAllocations);
            
            if (m_CurrentFrameGCAllocations > GCWarningThreshold)
            {
                Logger.LogWarning("GCMonitor", $"High GC allocation detected: {m_CurrentFrameGCAllocations} allocations this frame");
            }
        }
        
        m_LastGCCollectionCount = currentGCCollectionCount;
    }
    
    /// <summary>
    /// 更新GC统计信息
    /// </summary>
    private void UpdateGCStatistics()
    {
        if (m_CurrentFrameGCAllocations > 0)
        {
            Logger.Log("GCMonitor", $"GC Statistics - Max allocations per frame: {m_MaxFrameGCAllocations}, " +
                     $"Current frame: {m_CurrentFrameGCAllocations}");
        }
        
        m_CurrentFrameGCAllocations = 0;
    }
    
    /// <summary>
    /// 记录GC分配源
    /// </summary>
    public static void RecordGCAllocation(string source)
    {
        if (Instance == null) return;
        
        if (Instance.m_GCAllocationSources.ContainsKey(source))
        {
            Instance.m_GCAllocationSources[source]++;
        }
        else
        {
            Instance.m_GCAllocationSources[source] = 1;
        }
    }
    
    /// <summary>
    /// 获取GC统计信息
    /// </summary>
    public string GetGCStatistics()
    {
        var sb = StringBuilderPool.Get();
        sb.AppendLine("=== GC Statistics ===");
        sb.AppendLine($"Max allocations per frame: {m_MaxFrameGCAllocations}");
        sb.AppendLine($"Current frame allocations: {m_CurrentFrameGCAllocations}");
        sb.AppendLine($"Total GC collections: {System.GC.CollectionCount(0)}");
        sb.AppendLine($"Memory usage: {System.GC.GetTotalMemory(false) / 1024 / 1024} MB");
        
        if (m_GCAllocationSources.Count > 0)
        {
            sb.AppendLine("\n=== GC Allocation Sources ===");
            foreach (var kvp in m_GCAllocationSources)
            {
                sb.AppendLine($"{kvp.Key}: {kvp.Value} allocations");
            }
        }
        
        string result = sb.ToString();
        StringBuilderPool.Return(sb);
        return result;
    }
    
    /// <summary>
    /// 重置统计信息
    /// </summary>
    public void ResetStatistics()
    {
        m_CurrentFrameGCAllocations = 0;
        m_MaxFrameGCAllocations = 0;
        m_GCAllocationSources.Clear();
        m_LastGCCollectionCount = System.GC.CollectionCount(0);
    }
    
    /// <summary>
    /// 强制GC回收
    /// </summary>
    public void ForceGC()
    {
        System.GC.Collect();
        Logger.Log("GCMonitor", "Forced GC collection");
    }
    
    private void OnGUI()
    {
        if (!EnableMonitoring) return;
        
        GUILayout.BeginArea(new Rect(10, 10, 300, 200));
        GUILayout.Label("GC Monitor", GUI.skin.box);
        GUILayout.Label($"Max allocations/frame: {m_MaxFrameGCAllocations}");
        GUILayout.Label($"Current allocations: {m_CurrentFrameGCAllocations}");
        GUILayout.Label($"Memory: {System.GC.GetTotalMemory(false) / 1024 / 1024} MB");
        
        if (GUILayout.Button("Reset Stats"))
        {
            ResetStatistics();
        }
        
        if (GUILayout.Button("Force GC"))
        {
            ForceGC();
        }
        
        GUILayout.EndArea();
    }
}
